package vip.zhenzicheng.nio.nio;

import vip.zhenzicheng.nio.Const;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Set;

/**
 * NIO 通信服务端处理器
 *
 * @author zhenzicheng
 * @date: 2022-06-01 19:14
 */
public class NioServerHandle implements Runnable {

  private volatile boolean started;
  private ServerSocketChannel serverSocketChannel;
  private Selector selector;

  public NioServerHandle(int port) {
    try {
      // 选择器实例
      selector = Selector.open();
      serverSocketChannel = ServerSocketChannel.open();
      // 设置通道为非阻塞模式
      serverSocketChannel.configureBlocking(false);
      // 绑定端口
      serverSocketChannel.socket()
          .bind(new InetSocketAddress(port), 1024);
      // 注册事件，表示关心客户端连接
      serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

      started = true;
      System.out.println("服务器已启动,port:" + port);
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

  @Override
  public void run() {
    while (started) {
      try {
        selector.select(1000);
        Set<SelectionKey> selectionKeys = selector.selectedKeys();
        Iterator<SelectionKey> iterator = selectionKeys.iterator();
        while (iterator.hasNext()) {
          SelectionKey key = iterator.next();
          // 需要先删除再处理，防止重复处理
          iterator.remove();
          handleInput(key);
        }

      } catch (IOException e) {
        throw new RuntimeException(e);
      }
    }
  }

  private void handleInput(SelectionKey key) throws IOException {
    if (key.isValid()) {
      if (key.isAcceptable()) {
        // 获取当前关心事件的Channel
        ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
        // 接收连接
        SocketChannel sc = ssc.accept();
        System.out.println("==========连接建立==========");
        sc.configureBlocking(false);
        // 关注读事件
        sc.register(selector, SelectionKey.OP_READ);
      }
      // }

      if (key.isReadable()) {
        SocketChannel sc = (SocketChannel) key.channel();
        // 创建ByteBuffer，开辟一个缓冲区
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        int readBytes = sc.read(buffer);
        if (readBytes > 0) {
          buffer.flip(); // 转换读模式，从0-pos
          byte[] bytes = new byte[buffer.remaining()];
          buffer.get(bytes);

          String msg = new String(bytes, StandardCharsets.UTF_8);
          System.out.println("服务器收到消息：" + msg);
          // 处理数据
          String result = Const.response(msg);
          // 发送应答消息
          doWrite(sc, result);
        }
      }
    }
  }

  private void doWrite(SocketChannel sc, String response) throws IOException {
    byte[] bytes = response.getBytes();
    ByteBuffer buffer = ByteBuffer.allocate(bytes.length);
    buffer.put(bytes);
    buffer.flip();
    sc.write(buffer);
  }

  private void stop() {
    this.started = false;
  }
}
